package com.emotion.recognition.server.som;

import java.util.List;

public class SomMath {

	public static double calculateLearningRate(double initialLearningRate,
			int iteration, int maxEpochs) {
		return initialLearningRate
				* Math.exp(-1 * ((double) iteration / maxEpochs));
	}

	public static double calculateRadius(int mapRadius, int iteration,
			int maxEpochs) {
		return mapRadius
				* Math.exp(-1
						* ((double) iteration / (maxEpochs / Math
								.log(mapRadius))));
	}

	public static double calculateDistance(List<Double> input, FeatureNode node) {
		double sum = 0;
		for (int i = 0; i < input.size(); i++) {
			sum += Math.pow((input.get(i) - node.getWeights()[i]), 2);
		}
		return Math.sqrt(sum);
	}

	public static double calculateInfluence(double distanceSquared,
			double radius) {
		return Math.exp(-1 * (distanceSquared / (2 * (Math.pow(radius, 2)))));
	}

	/**
	 * Used to calculate the new weight for a particular weight in a feature
	 * node.
	 * 
	 * @param inputValue
	 * @param nodeWeight
	 * @param learningRate
	 * @param influence
	 * @return the weight
	 */
	public static double calculateNewWeight(double inputValue,
			double nodeWeight, double learningRate, double influence) {
		return (nodeWeight + (influence * learningRate * (inputValue - nodeWeight)));
	}

	/**
	 * Used to calculate the distance squared between nodeA, which is the BMU,
	 * and nodeB, which is another node in the feature map.
	 * 
	 * @param nodeA
	 * @param nodeB
	 * @return distance squared
	 */
	public static double calculateDistanceSquared(FeatureNode nodeA,
			FeatureNode nodeB) {
		return Math.pow(nodeA.getPositionX() - nodeB.getPositionX(), 2)
				+ Math.pow(nodeA.getPositionY() - nodeB.getPositionY(), 2);
	}
}
